import pandas as pd
import numpy as np
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import xgboost as xgb

# 1. 读取数据
data = pd.read_excel(r"C:\Users\Lenovo\Desktop\共线性处理与标准化后数据.xlsx")

# 2. 划分特征和目标变量
X = data[["年龄", "身高", "孕妇BMI（处理后）", "检测孕周(处理后)"]]
y = data["达标时间"]

# 3. 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 4. 定义 XGBoost 回归模型
xgb_model = xgb.XGBRegressor(random_state=42)

# 5. 优化参数网格：缩小范围，减少候选组合
param_grid = {
    'n_estimators': [50, 100],  # 减少树的数量候选
    'learning_rate': [0.05, 0.1],  # 调整学习率范围
    'max_depth': [3, 4],  # 减少树深度候选
    'subsample': [0.7, 0.8],  # 调整子样本比例
    'colsample_bytree': [0.7, 0.8]  # 调整列采样比例
}

# 6. 调整交叉验证折数，平衡效率与准确性
grid_search = GridSearchCV(
    estimator=xgb_model,
    param_grid=param_grid,
    cv=3,  # 从 5 折减为 3 折
    scoring='neg_mean_squared_error',
    verbose=1
)
grid_search.fit(X_train, y_train)

# 7. 获取最佳参数和最佳模型
best_params = grid_search.best_params_
best_model = grid_search.best_estimator_
print("最佳参数：", best_params)

# 8. 在测试集上进行预测
y_pred = best_model.predict(X_test)

# 9. 模型评估
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print("均方误差（MSE）：", mse)
print("平均绝对误差（MAE）：", mae)
print("决定系数（R²）：", r2)

# 10. 分析特征重要性
feature_importance = best_model.feature_importances_
feature_names = X.columns
importance_df = pd.DataFrame({
    '特征': feature_names,
    '重要性': feature_importance
})
importance_df = importance_df.sort_values('重要性', ascending=False)
print("\n特征重要性：")
print(importance_df)

# 11. 分析包含体重的特征重要性（若需）
original_data = pd.read_excel(r"C:\Users\Lenovo\Desktop\含达标时间的男胎数据.xlsx")
X_with_weight = original_data[["年龄", "身高", "体重", "孕妇BMI（处理后）", "检测孕周(处理后)"]]
y_with_weight = original_data["达标时间"]

X_train_with_weight, X_test_with_weight, y_train_with_weight, y_test_with_weight = train_test_split(
    X_with_weight, y_with_weight, test_size=0.3, random_state=42
)

xgb_model_with_weight = xgb.XGBRegressor(**best_params, random_state=42)
xgb_model_with_weight.fit(X_train_with_weight, y_train_with_weight)

feature_importance_with_weight = xgb_model_with_weight.feature_importances_
feature_names_with_weight = X_with_weight.columns
importance_with_weight_df = pd.DataFrame({
    '特征': feature_names_with_weight,
    '重要性': feature_importance_with_weight
})
importance_with_weight_df = importance_with_weight_df.sort_values('重要性', ascending=False)
print("\n包含体重的特征重要性：")
print(importance_with_weight_df)







import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
import xgboost as xgb

# -------------------------- 1. 读取数据（仅使用不含体重的处理后数据） --------------------------
# 数据路径：目标文件路径
data = pd.read_excel(r"C:\Users\Lenovo\Desktop\共线性处理与标准化后数据.xlsx")

# 2. 划分特征和目标变量（仅保留四大因素，不含体重）
X = data[["年龄", "身高", "孕妇BMI（处理后）", "检测孕周(处理后)"]]
y = data["达标时间"]

# 3. 划分训练集和测试集（7:3比例，保证结果可复现）
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)
print(f"训练集样本数：{len(X_train)}，测试集样本数：{len(X_test)}")

# -------------------------- 4. XGBoost模型构建与参数调优 --------------------------
# 4.1 定义基础模型
xgb_model = xgb.XGBRegressor(random_state=42)

# 4.2 优化参数网格（平衡效率与精度）
param_grid = {
    'n_estimators': [50, 100],    # 树的数量
    'learning_rate': [0.05, 0.1], # 学习率
    'max_depth': [3, 4],          # 树最大深度
    'subsample': [0.7, 0.8],      # 子样本比例
    'colsample_bytree': [0.7, 0.8]# 列采样比例
}

# 4.3 网格搜索（3折交叉验证）
grid_search = GridSearchCV(
    estimator=xgb_model,
    param_grid=param_grid,
    cv=3,
    scoring='neg_mean_squared_error',
    verbose=1
)
grid_search.fit(X_train, y_train)

# 4.4 获取最佳模型与参数
best_params = grid_search.best_params_
best_model = grid_search.best_estimator_
print(f"\n最佳参数：{best_params}")

# -------------------------- 5. 模型评估 --------------------------
# 5.1 测试集预测
y_pred = best_model.predict(X_test)

# 5.2 计算评估指标
mse = mean_squared_error(y_test, y_pred)
mae = mean_absolute_error(y_test, y_pred)
r2 = r2_score(y_test, y_pred)
print(f"\n模型评估结果：")
print(f"均方误差（MSE）：{mse:.4f}")
print(f"平均绝对误差（MAE）：{mae:.4f}")
print(f"决定系数（R²）：{r2:.4f}")

# -------------------------- 6. 特征重要性分析与可视化 --------------------------
# 6.1 提取特征重要性
feature_importance = best_model.feature_importances_
feature_names = X.columns
# 整理为DataFrame并排序
importance_df = pd.DataFrame({
    '特征': feature_names,
    '重要性': feature_importance
}).sort_values('重要性', ascending=False)
print(f"\n四大因素特征重要性排序：")
print(importance_df)

# 6.2 特征重要性可视化（水平柱状图）
# 设置中文字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 创建图表
fig, ax = plt.subplots(figsize=(10, 6))
# 自定义配色
colors = ['#2E86AB', '#A23B72', '#F18F01', '#C73E1D']
# 绘制柱状图
bars = ax.barh(
    importance_df['特征'],
    importance_df['重要性'],
    color=colors,
    alpha=0.8
)

# 添加数值标签
for bar in bars:
    width = bar.get_width()
    ax.text(
        width + 0.005,
        bar.get_y() + bar.get_height()/2,
        f'{width:.3f}',
        va='center',
        fontsize=11
    )

# 设置图表样式
ax.set_title('XGBoost模型特征重要性（不含体重）', fontsize=14, fontweight='bold', pad=20)
ax.set_xlabel('特征重要性值', fontsize=12)
ax.set_xlim(0, max(importance_df['重要性']) + 0.05)
ax.grid(axis='x', alpha=0.3)

# 保存图表
plt.tight_layout()
plt.savefig(
    r"C:\Users\Lenovo\Desktop\不含体重_特征重要性可视化.png",
    dpi=300,
    bbox_inches='tight'
)
plt.show()
print(f"\n特征重要性图表已保存至：C:\\Users\\Lenovo\\Desktop\\不含体重_特征重要性可视化.png")

# -------------------------- 7. 保存模型与结果 --------------------------
# 保存最佳模型（可选）
import joblib
joblib.dump(best_model, r"C:\Users\Lenovo\Desktop\不含体重_XGBoost最佳模型.pkl")
# 保存特征重要性结果
importance_df.to_excel(
    r"C:\Users\Lenovo\Desktop\不含体重_特征重要性结果.xlsx",
    index=False
)
print(f"最佳模型已保存至：C:\\Users\\Lenovo\\Desktop\\不含体重_XGBoost最佳模型.pkl")
print(f"特征重要性结果已保存至：C:\\Users\\Lenovo\\Desktop\\不含体重_特征重要性结果.xlsx")
